package com.sinog.auth.service;

import com.sinog.auth.entity.AuthUser;
import com.sinog.auth.feign.UserLoginCheckService;
import com.sinog.auth.repository.SystemUserRepository;
import com.sinog.auth.util.CodeUrlUtils;
import com.sinog.auth.util.TokenParseUtils;
import com.sinog.core.utilbean.Constants;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @desc 用户信息基础接口
 * @author zy
 * @date 2019年8月15日 11点17分
 */
public abstract class BaseUserDetailService implements UserDetailsService {

    /**
     * 登录用户的默认授权角色
     */
    private static final String ROLE_LOGIN = "ROLE_LOGIN";
    @Autowired
    private UserLoginCheckService userLoginCheckService;
    @Autowired
    private SystemUserRepository systemUserRepository;
    /**
     * 是否使用验证码  true 使用  false  不使用
     */
    @Value("${gkzx.azbj.captcha.use.state}")
    private boolean captchaUseState;
    /**
     * 锁定时间
     */
    @Value("${gkzx.azbj.captcha.locktime}")
    private Integer captchaLockTime;
    /**
     * 锁定次数
     */
    @Value("${gkzx.azbj.captcha.locknum}")
    private Integer captchaLockNum;
    /**
     * 单点登录方式
     * 1: 明文手机号
     * 2： AES解密 手机号
     * 3: jwt解密
     * 4: 关闭
     */
    @Value("${gkzx.azbj.sso.type}")
    private Integer ssoType;
    /**
     * 秘钥
     */
    @Value("${gkzx.azbj.sso.singeKey}")
    private String singeKey;

    /**
     * 描述
     * @param var1 var1
     * @return UserDetails
     */
    @Override
    public UserDetails loadUserByUsername(String var1) {
        HttpServletRequest request = ((ServletRequestAttributes)Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        AuthUser baseUser;
        String account = null;
        try {
            //山西
            String localCode = CodeUrlUtils.getLocalCode();
            String token;
            if(Constants.XzqhCode.SHAN1XI.equals(localCode)) {
                token = request.getParameter("mobile");
            } else {
                token = request.getParameter("token");
            }
            if(StringUtils.isNotBlank(token)) {
                //判断是否单点登录 1:明文 手机号 2:密文 Aes解密手机号 3: jwt解密账号 4是关闭
                if(Constants.Number.NUM_FOUR.equals(ssoType)) {
                    baseUser = getUser(var1);
                } else {
                    // 解析方式
                    if(Constants.Number.NUM_ONE.equals(ssoType)) {
                        account = systemUserRepository.findAccountByPhone(token);
                    } else if(Constants.Number.NUM_TWO.equals(ssoType)) {
                        String decryptToken = null;
                        try {
                            decryptToken = TokenParseUtils.decryptStr(token,singeKey);
                        } catch(Exception e) {
                            request.getSession().setAttribute("code","402");
                        }
                        account = systemUserRepository.findAccountByPhone(decryptToken);
                    } else if(Constants.Number.NUM_THREE.equals(ssoType)) {
                        Map<String,Object> expand=TokenParseUtils.jwtParseToken(token,singeKey);
                        String areaCode = (String)expand.get("areaCode");
                        String deptLevel = (String)expand.get("deptLevel");
                        if(Constants.NumberStr.NUM_STR_YUNNAN_SFT.equals(deptLevel)){
                            areaCode = areaCode.substring(0,areaCode.length()-6);
                        } else if(Constants.NumberStr.NUM_STR_YUNNAN_DSSFJ.equals(deptLevel)){
                            areaCode = areaCode.substring(0,areaCode.length()-6);
                        } else if(Constants.NumberStr.NUM_STR_YUNNAN_QXSFJ.equals(deptLevel)){
                            areaCode = areaCode.substring(0,areaCode.length()-6);
                        } else if(Constants.NumberStr.NUM_STR_YUNNAN_SFS.equals(deptLevel)){
                            areaCode = areaCode.substring(0,areaCode.length()-3);
                        }
                        //根据部门id查询账号
                        account = systemUserRepository.findAccountByDepartid(areaCode);
                    }
                    baseUser = getUser(account);
                }
            } else {
                baseUser = getUser(var1);
            }
            if(StringUtils.isBlank(account)) {
                String ip = request.getHeader("X-Forwarded-For");
                // 取不到forwarded地址就取实际的ip地址
                if(null == ip || ip.isEmpty()) {
                    ip = request.getRemoteAddr();
                } else {
                    // 如果有多级反向代理，返回的是一组ip，取第一个
                    ip = ip.split(",")[0];
                }
                if(captchaUseState) {
                    //前端输入的验证码
                    String captchaForward = request.getParameter("captcha").toLowerCase();
                    //图片真实验证码
                    String captchaBack = "";
                    Object captcha = request.getSession().getAttribute("captcha");
                    boolean flag = userLoginCheckService.getUserLockState(baseUser.getAccount(),captchaLockNum,captchaLockTime);
                    if(flag) {
                        request.getSession()
                               .setAttribute("username_err","连续" + captchaLockNum + "次登录错误，请" + captchaLockTime + "分钟后重试!");
                        userLoginCheckService.insertUserLoginDetails(baseUser.getAccount(),ip,"2","多次登录错误，被锁定5分钟");
                        throw new RuntimeException("连续" + captchaLockNum + "次登录错误，请" + captchaLockTime + "分钟后重试!");
                    }
                    if(null != captcha) {
                        captchaBack = request.getSession().getAttribute("captcha").toString().toLowerCase();
                    }
                    if(StringUtils.isEmpty(captchaForward)) {
                        request.getSession().setAttribute("username_err","请输入验证码!");
                        userLoginCheckService.insertUserLoginDetails(baseUser.getAccount(),ip,"2","未输入验证码");
                        throw new RuntimeException("请输入验证码!");
                    }
                    if(!StringUtils.equals(captchaForward,captchaBack)) {
                        request.getSession().setAttribute("username_err","验证码不正确,请重新输入!");
                        userLoginCheckService.insertUserLoginDetails(baseUser.getAccount(),ip,"2","验证码不正确");
                        throw new RuntimeException("验证码不正确,请重新输入!");
                    }
                }
            }
            // 获取用户权限列表
            List<GrantedAuthority> authorities = new ArrayList<>(16);
            authorities.add(new SimpleGrantedAuthority(ROLE_LOGIN));
            // 返回带有用户权限信息的User
            request.getSession().setAttribute("username_err","");
            return new User(baseUser.getAccount(),baseUser.getPassword(),authorities);
        } catch(UsernameNotFoundException e) {
            request.getSession().setAttribute("username_err","用户名或密码错误");
            throw new UsernameNotFoundException("用户名或密码错误");
        }
    }

    /**
     * 获取授权用户
     * @param username username
     * @return AuthUser
     */
    protected abstract AuthUser getUser(String username);
}